package com.cjj.refresh;

import com.ryan.ohos.extension.event.DispatchHelper;
import com.ryan.ohos.extension.event.impl.ViewGroupHelper;
import com.ryan.ohos.extension.event.interfaces.ViewGroup;

import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.*;
import ohos.agp.utils.LayoutAlignment;
import ohos.app.Context;

import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

import ohos.multimodalinput.event.TouchEvent;

/**
 * RefreshLayout
 *
 * @author cjj
 * @since 2015/8/4
 */
public class RefreshLayout extends StackLayout implements Component.TouchEventListener,
        Component.BindStateChangedListener, ViewGroup {
    /**
     * 波浪的高度
     */
    protected float mWaveHeight;

    /**
     * 头部的高度
     */
    protected float mHeadHeight;

    /**
     * 子控件
     */
    private Component mChildView;

    /**
     * 头部layout
     */
    protected StackLayout mHeadLayout;

    /**
     * 刷新的状态
     */
    protected boolean isRefreshing;

    /**
     * 触摸获得Y的位置
     */
    private float mTouchY;

    /**
     * 触发Touch事件的触控点Id
     */
    protected int mActivePointerId = INVALID_POINTER;

    // 触控点无效标志
    private static final int INVALID_POINTER = 0;

    // 动画的变化率
    private DecelerateInterpolator decelerateInterpolator;

    private final EventHandler eventHandler = new EventHandler(EventRunner.getMainEventRunner());

    private ViewGroupHelper viewGroupHelper;

    public RefreshLayout(Context context) {
        this(context, null, null);
    }

    public RefreshLayout(Context context, AttrSet attrs) {
        this(context, attrs, null);
    }

    public RefreshLayout(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    /**
     * 初始化
     *
     * @throws RuntimeException limitChildCount
     */
    private void init() {
        viewGroupHelper = new ViewGroupHelper(this);
        setBindStateChangedListener(this);
        if (getChildCount() > 1) {
            throw new RuntimeException("只能拥有一个子控件哦");
        }
        // 在动画开始的地方快然后慢;
        decelerateInterpolator = new DecelerateInterpolator(10);
        // 添加头部
        StackLayout headViewLayout = new StackLayout(getContext());
        LayoutConfig layoutParams = new LayoutConfig(LayoutConfig.MATCH_PARENT, 0);
        layoutParams.alignment = LayoutAlignment.TOP;
        headViewLayout.setLayoutConfig(layoutParams);
        mHeadLayout = headViewLayout;
        setTouchEventListener(this);
    }

    @Override
    public void onComponentBoundToWindow(Component component) {
        // 添加头部
        this.addComponent(mHeadLayout);
//
        // 获得子控件
        mChildView = getComponentAt(0);
    }

    @Override
    public void onComponentUnboundFromWindow(Component component) {
    }

    private void setChildViewTransLationY(float values) {
        int currHeight = (int) mChildView.getTranslationY();    // 获得mChildView当前y的位置
        AnimatorValue oa = new AnimatorValue();
        oa.setDuration(1000);
        oa.setCurve(decelerateInterpolator);
        oa.setValueUpdateListener((animatorValue, value) -> {
            mChildView.setTranslationY(currHeight + ((values - currHeight) * value));
            int height = (int) mChildView.getTranslationY();    // 获得mChildView当前y的位置
            LayoutConfig lp = (LayoutConfig) mHeadLayout.getLayoutConfig();
            lp.height = height;
            mHeadLayout.setLayoutConfig(lp);
            mHeadLayout.postLayout();   // 重绘

            if (pullWaveListener != null) {
                pullWaveListener.onPullReleasing(RefreshLayout.this, height / mHeadHeight);
            }
        });
        oa.start();
    }

    @Override
    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
        viewGroupHelper.requestDisallowInterceptTouchEvent(disallowIntercept);
    }

    @Override
    public boolean onInterceptTouchEvent(TouchEvent ev) {
        if (isRefreshing) {
            return true;
        }
        switch (ev.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                mTouchY = ev.getPointerPosition(ev.getIndex()).getY();
                break;
            case TouchEvent.POINT_MOVE:
                float currentY = ev.getPointerPosition(ev.getIndex()).getY();
                float dy = (float) (currentY - (double) mTouchY);
                if (dy > 0 && !canChildScrollUp()) {
                    return true;
                }
                break;
        }
        return false;
    }

    @Override
    public boolean dispatchTouchEvent(TouchEvent event) {
        return viewGroupHelper.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(TouchEvent touchEvent) {
        if (isRefreshing) {
            setListContainerScroll(false);
            return true;
        }
        switch (touchEvent.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                mTouchY = touchEvent.getPointerScreenPosition(touchEvent.getIndex()).getY();
                break;
            case TouchEvent.POINT_MOVE:
                // 获得当前touch事件index
                int index = touchEvent.getIndex();
                // 获得当前touch事件触控点Id
                mActivePointerId = touchEvent.getPointerId(index);
                float currentY = touchEvent.getPointerScreenPosition(touchEvent.getIndex()).getY();
                float dy = (float) (currentY - (double) mTouchY);
                if (dy > 0 && !canChildScrollUp()) {
                    dy = Math.min(mWaveHeight * 2, dy);
                    dy = Math.max(0, dy);
                    if (mChildView != null) {
                        float offsetY = decelerateInterpolator.getCurvedTime(dy / mWaveHeight / 2) * dy / 2;
                        mChildView.setTranslationY(offsetY);
                        LayoutConfig lp = (LayoutConfig) mHeadLayout.getLayoutConfig();
                        lp.height = (int) offsetY;
                        mHeadLayout.setLayoutConfig(lp);
                        mHeadLayout.postLayout();

                        if (pullWaveListener != null) {
                            pullWaveListener.onPulling(RefreshLayout.this, offsetY / mHeadHeight);
                        }
                    }
                }
                return true;
            case TouchEvent.CANCEL:
            case TouchEvent.PRIMARY_POINT_UP:
                if (mChildView != null) {
                    if (mChildView.getTranslationY() >= mHeadHeight) {
                        setChildViewTransLationY(mHeadHeight);
                        isRefreshing = true;
                        if (pullToRefreshPullingListener != null) {
                            pullToRefreshPullingListener.onRefresh(RefreshLayout.this);
                        }
                    } else {
                        setChildViewTransLationY(0);
                    }
                }
                return true;
        }
        return true;
    }

    @Override
    public boolean isConsumed() {
        return viewGroupHelper.isConsumed();
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        return DispatchHelper.dispatch(component, touchEvent);
    }

    private void setListContainerScroll(boolean isScroll) {
        if (mChildView != null && mChildView instanceof ListContainer) {
            mChildView.setEnabled(isScroll);
        }
    }

    /**
     * 用来判断是否可以上拉
     *
     * @return boolean
     */
    public boolean canChildScrollUp() {
        if (mChildView == null) {
            return false;
        }
        return mChildView.canScroll(DRAG_DOWN);  // 判断
    }

    /**
     * 设置下拉监听
     */
    private PullToRefreshListener pullToRefreshPullingListener;

    /**
     * setPullToRefreshListener
     *
     * @param pullToRefreshPullingListener pullToRefreshPullingListener
     */
    public void setPullToRefreshListener(PullToRefreshListener pullToRefreshPullingListener) {
        this.pullToRefreshPullingListener = pullToRefreshPullingListener;
    }

    /**
     * 设置wave监听
     */
    private PullWaveListener pullWaveListener;

    public void setPullWaveListener(PullWaveListener pullWaveListener) {
        this.pullWaveListener = pullWaveListener;
    }

    /**
     * 刷新结束
     */
    public void finishRefreshing() {
        if (mChildView != null) {
            setChildViewTransLationY(0);
            setListContainerScroll(true);
        }
        isRefreshing = false;
    }

    /**
     * 设置头部View
     *
     * @param headerView headerView
     */
    public void setHeaderView(final Component headerView) {
        eventHandler.postTask(() -> mHeadLayout.addComponent(headerView));
    }

    /**
     * 设置wave的下拉高度
     *
     * @param waveHeight waveHeight
     */
    public void setWaveHeight(float waveHeight) {
        this.mWaveHeight = waveHeight;
    }

    /**
     * 设置下拉头的高度
     *
     * @param headHeight headHeight
     */
    public void setHeaderHeight(float headHeight) {
        this.mHeadHeight = headHeight;
    }
}
